#include "StdAfx.h"
#include "Input.h"
#include "Game.h"
// TODO remove game

DECLARE_SINGLETON_CPP(Input);

static char KeycodeToASCII(byte _scancode)
{
	static HKL Layout = GetKeyboardLayout(0);
	static unsigned char State[256];
	unsigned short result;

	GetKeyboardState(State);

	unsigned int VK = MapVirtualKeyEx(_scancode, 1, Layout);

	if (ToAsciiEx(VK, _scancode, State, &result, 0, Layout) == 0)
		result = 0;

	return (char)result;
}

Input::Input(void)
{
	// TODO
	ZeroMemory(this, sizeof(Input));
}

Input::~Input(void)
{

}

// todo take out include game.h and pass in application and window
void Input::Init()
{
	XInputEnable(true);

	DirectInput8Create(Game::GetInstance()->GetApplication(), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, 0);
	
	// keyboard
	din->CreateDevice(GUID_SysKeyboard, &kb, NULL);
	kb->SetDataFormat(&c_dfDIKeyboard);
	kb->SetCooperativeLevel(Game::GetInstance()->GetWindow(), DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
	kb->Acquire();

	// mouse
	din->CreateDevice(GUID_SysMouse, &mouse, NULL);
	mouse->SetDataFormat(&c_dfDIMouse);
	mouse->SetCooperativeLevel(Game::GetInstance()->GetWindow(), DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
	mouse->Acquire();

	WINDOWPLACEMENT wp;
	GetWindowPlacement(Game::GetInstance()->GetWindow(), &wp);
	POINT p;
	GetCursorPos(&p);
	cursorPos.x = (float)p.x - (float)wp.rcNormalPosition.left;
	cursorPos.y = (float)p.y - (float)wp.rcNormalPosition.top;

	//ShowCursor(FALSE);
	//SetCursorPos(400 + wp.rcNormalPosition.left, 300 + wp.rcNormalPosition.top);

	/*din->EnumDevices(DI8DEVCLASS_GAMECTRL, &FoundGamepad, 
		NULL, DIEDFL_ATTACHEDONLY);

	g_pJoy->SetDataFormat(&c_dfDIJoystick);
	g_pJoy->SetCooperativeLevel(g_hWindow, DISCL_EXCLUSIVE | DISCL_FOREGROUND);*/
}

void Input::Shutdown()
{
	XInputEnable(false);

	SAFE_RELEASE_INPUT(kb);
	SAFE_RELEASE_INPUT(mouse);
	SAFE_RELEASE(din);
}

void Input::Update()
{
	ZeroMemory(prevKeys, sizeof(prevKeys));
	memcpy((void*)prevKeys, (void*)keys, 256);
	kb->Acquire();
	ZeroMemory(keys, sizeof(keys));
	kb->GetDeviceState(sizeof(keys), (void*)keys);

	memcpy((void*)&prevMouseState, (void*)&mouseState, sizeof(DIMOUSESTATE));
	mouse->Acquire();
	mouse->GetDeviceState(sizeof(DIMOUSESTATE), (void*)&mouseState);
	
	cursorChange.x = (float)mouseState.lX;
	cursorChange.y = (float)mouseState.lY;
	cursorPos += cursorChange;

	//cursorPos += cursorChange;

	//for (unsigned int i = 0; i < _countof(controllers); ++i)
	//{
	//	memcpy((void*)&controllers[i].prevXstate, (void*)&controllers[i].Xstate, sizeof(XINPUT_STATE));
	//	if (ERROR_DEVICE_NOT_CONNECTED == XInputGetState(i, &controllers[i].Xstate))
	//	{
	//		controllers[i].connected = false;
	//	}
	//	else
	//	{
	//		controllers[i].connected = true;

	//		// deadzone fix
	//		if(controllers[i].Xstate.Gamepad.sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && controllers[i].Xstate.Gamepad.sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
	//			controllers[i].Xstate.Gamepad.sThumbLX = 0;
	//		if(controllers[i].Xstate.Gamepad.sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && controllers[i].Xstate.Gamepad.sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
	//			controllers[i].Xstate.Gamepad.sThumbLY = 0;

	//		if(controllers[i].Xstate.Gamepad.sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && controllers[i].Xstate.Gamepad.sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
	//			controllers[i].Xstate.Gamepad.sThumbRX = 0;
	//		if(controllers[i].Xstate.Gamepad.sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && controllers[i].Xstate.Gamepad.sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
	//			controllers[i].Xstate.Gamepad.sThumbRY = 0;

	//		if (controllers[i].Xstate.Gamepad.bLeftTrigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
	//			controllers[i].Xstate.Gamepad.bLeftTrigger = 0;
	//		if (controllers[i].Xstate.Gamepad.bRightTrigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
	//			controllers[i].Xstate.Gamepad.bRightTrigger = 0;

	//		// vibration
	//		if (controllers[i].vibrating)
	//		{
	//			controllers[i].vibratingTime = max(0.0f, controllers[i].vibratingTime);
	//			if (controllers[i].vibratingTime == 0.0f)
	//			{
	//				controllers[i].vibrating = false;
	//				XINPUT_VIBRATION vibration;
	//				vibration.wLeftMotorSpeed = 0;
	//				vibration.wRightMotorSpeed = 0;
	//				XInputSetState(i, &vibration);
	//			}
	//		}
	//	}
	//}	
}

bool Input::IsAGamepadButtonPressed(const DWORD _index)
{
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_START, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_BACK, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_UP, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_DOWN, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_LEFT, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_RIGHT, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_A, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_B, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_X, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_Y, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_RIGHT_SHOULDER, _index))
		return true;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_LEFT_SHOULDER, _index))
		return true;

	return false;
}

WORD Input::GetGamepadButtonDown(const DWORD _index)
{
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_START, _index))
		return XINPUT_GAMEPAD_START;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_BACK, _index))
		return XINPUT_GAMEPAD_BACK;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_DPAD_UP, _index))
		return XINPUT_GAMEPAD_DPAD_UP;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_DPAD_DOWN, _index))
		return XINPUT_GAMEPAD_DPAD_DOWN;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_DPAD_LEFT, _index))
		return XINPUT_GAMEPAD_DPAD_LEFT;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_DPAD_RIGHT, _index))
		return XINPUT_GAMEPAD_DPAD_RIGHT;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_A, _index))
		return XINPUT_GAMEPAD_A;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_B, _index))
		return XINPUT_GAMEPAD_B;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_X, _index))
		return XINPUT_GAMEPAD_X;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_Y, _index))
		return XINPUT_GAMEPAD_Y;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_RIGHT_THUMB, _index))
		return XINPUT_GAMEPAD_RIGHT_SHOULDER;
	if (IsGamepadButtonDown(XINPUT_GAMEPAD_LEFT_THUMB, _index))
		return XINPUT_GAMEPAD_LEFT_SHOULDER;

	return 0;
}

WORD Input::GetGamepadButtonPressed(const DWORD _index)
{
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_START, _index))
		return XINPUT_GAMEPAD_START;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_BACK, _index))
		return XINPUT_GAMEPAD_BACK;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_UP, _index))
		return XINPUT_GAMEPAD_DPAD_UP;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_DOWN, _index))
		return XINPUT_GAMEPAD_DPAD_DOWN;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_LEFT, _index))
		return XINPUT_GAMEPAD_DPAD_LEFT;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_DPAD_RIGHT, _index))
		return XINPUT_GAMEPAD_DPAD_RIGHT;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_A, _index))
		return XINPUT_GAMEPAD_A;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_B, _index))
		return XINPUT_GAMEPAD_B;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_X, _index))
		return XINPUT_GAMEPAD_X;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_Y, _index))
		return XINPUT_GAMEPAD_Y;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_RIGHT_SHOULDER, _index))
		return XINPUT_GAMEPAD_RIGHT_SHOULDER;
	if (IsGamepadButtonPressed(XINPUT_GAMEPAD_LEFT_THUMB, _index))
		return XINPUT_GAMEPAD_LEFT_SHOULDER;

	return 0;
}

void Input::ResetGamepadThumbsticks(const DWORD _index)
{ 
	controllers[_index].Xstate.Gamepad.sThumbLX = controllers[_index].Xstate.Gamepad.sThumbLY = controllers[_index].Xstate.Gamepad.sThumbRX = controllers[_index].Xstate.Gamepad.sThumbRY = 0;
	controllers[_index].prevXstate.Gamepad.sThumbLX = controllers[_index].prevXstate.Gamepad.sThumbLY = controllers[_index].prevXstate.Gamepad.sThumbRX = controllers[_index].prevXstate.Gamepad.sThumbRY = 0;
}

void Input::ResetGamepadTriggers(const DWORD _index)
{
	controllers[_index].Xstate.Gamepad.bLeftTrigger = controllers[_index].Xstate.Gamepad.bRightTrigger = 0;
	controllers[_index].prevXstate.Gamepad.bLeftTrigger = controllers[_index].prevXstate.Gamepad.bRightTrigger = 0;
}

void Input::VibrateGamepad(const float _time, const float _leftSpeed, const float _rightSpeed, const DWORD _index)
{
	XINPUT_VIBRATION vibration;
	vibration.wLeftMotorSpeed = (WORD)(_leftSpeed * 65535.0f);
	vibration.wRightMotorSpeed = (WORD)(_rightSpeed * 65535.0f);
	if (XInputSetState(_index, &vibration) == 0)
	{
		controllers[_index].vibrating = true;
		controllers[_index].vibratingTime = _time;
	}
}

void Input::StopVibratingGamepad(const DWORD _index)
{
	XINPUT_VIBRATION vibration;
	vibration.wLeftMotorSpeed = 0;
	vibration.wRightMotorSpeed = 0;
	XInputSetState(_index, &vibration);
	controllers[_index].vibrating = false;
	controllers[_index].vibratingTime = 0.0f;
}


bool Input::IsAKeyDown() const
{
	for (unsigned int i = 0; i < 256; ++i)
	{
		if (KEYDOWN(keys, i))
		{
			return true;
		}
	}

	return false;
}

bool Input::IsAKeyPressed() const
{
	for (unsigned int i = 0; i < 256; ++i)
	{
		if (KEYDOWN(prevKeys, i) && KEYUP(keys, i))
		{
			return true;
		}
	}

	return false;
}

char Input::GetKeyDownASCII() const
{
	for (unsigned int i = 0; i < 256; ++i)
	{
		if (KEYDOWN(keys, i))
		{
			return KeycodeToASCII((byte)i);
		}
	}

	return 0;
}

char Input::GetKeyPressedASCII() const
{
	for (unsigned int i = 0; i < 256; ++i)
	{
		if (KEYDOWN(prevKeys, i) && KEYUP(keys, i))
		{
			return KeycodeToASCII((byte)i);
		}
	}

	return 0;
}

byte Input::GetKeyDown() const
{
	for (unsigned int i = 0; i < 256; ++i)
	{
		if (KEYDOWN(keys, i))
		{
			return (byte)i;
		}
	}

	return 0;
}

byte Input::GetKeyPressed() const
{
	for (unsigned int i = 0; i < 256; ++i)
	{
		if (KEYDOWN(prevKeys, i) && KEYUP(keys, i))
		{
			return (byte)i;
		}
	}

	return 0;
}